const fs = require('fs')
const EventEmitter = require('events')
const Queue = require('./linkedlist')

class MyWriteStream extends EventEmitter{
  constructor(path, options={}){
    super()
    this.path = path
    this.flags = options.flags || 'w'
    this.mode = options.mode || 438
    this.autoClose = options.autoClose || true
    this.start = options.start || 0
    this.encoding = options.encoding || 'utf8'
    this.highWaterMark = options.highWaterMark || 16*1024

    this.open()

    this.writeoffset = this.start
    this.writing = false
    this.writeLen = 0
    this.needDrain = false
    this.cache = new Queue()
  }
  open(){
    // 原生fs.open
    fs.open(this.path, this.flags, (err,fd)=>{
      if(err){
        console.log('open错误',err)
        return;
      }
      this.fd = fd
      this.emit('open',fd)
    })
  }
  write(chunk, encoding, cb){
    // 统一chunk类型 这里默认用户只会输入buffer和字符串
    chunk = Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk)
    // 统计累计写入量
    this.writeLen += chunk.length
    // 返回水位线警告标识
    let flag = this.writeLen<this.highWaterMark
    // needDrain为flag的取反
    this.needDrain = !flag

    if(this.writing){
      // 正在执行写入，内容排队
      this.cache.enQueue({chunk,encoding,cb})
    }else{
      this.writing = true
      // 当前非写入状态，执行写入
      this._write(chunk, encoding, ()=>{
        cb()
        // 清空排队的内容
        this._clearBuffer()
      })
    }

    return flag
  }
  _write(chunk, encoding, cb){
    // fd不为数值，表示open方法读取文件中(异步行为)
    if(typeof this.fd !== 'number'){
      // open事件响应 递归调用 以调整代码执行顺序
      return this.once('open', ()=>{
        this._write(chunk, encoding, cb)
      })
    }
    fs.write(this.fd, chunk, this.start, chunk.length, this.writeoffset, (err,written)=>{
      //更新写入位置
      this.writeoffset+=written
      //更新待写入长度
      this.writeLen-=written
      cb&&cb()
    })
  }
  _clearBuffer(){
    let data = this.cache.deQueue()
    if(data){
      // 有数据 执行写操作
      var el = data.element
      this._write(data.element.chunk, data.element.encoding, ()=>{
        data.element.cb&&data.element.cb()
        // 继续清队列
        this._clearBuffer()
      })
    }else{
      // 无数据 表示队列中的数据写完了
      // 根据needDrain属性触发drain事件
      if(this.needDrain){
        this.needDrain = false
        this.emit('drain')
      }
    }
  }
}

const ws = new MyWriteStream('./test.txt',{
  highWaterMark: 2
})

ws.on('open', (fd)=>{
  console.log('open事件',fd)
})

ws.write('1', 'utf8', ()=>{
  console.log('写入ok')
})
ws.write('234', 'utf8', ()=>{
  console.log('写入ok2')
})
ws.write('世界和平', 'utf8', ()=>{
  console.log('写入ok3')
})
ws.on('drain',()=>{
  console.log('drain事件')
})
